home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / BaseConverter 1.1 / BaseConverter 1.1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-06  |  38.5 KB  |  1,783 lines  |  [TEXT/KAHL]

  1. /*    BaseConverter90 1.0d14.c */
  2. /*    Roger Brown
  3.       Courseware Development Group
  4.       Dartmouth College
  5.     
  6.     Written in THINK C ®Symantec Corp.
  7.     
  8.  version 1.1 5/6/94
  9.  Added a font menu for all input fields. It is semi-smart about keyboards.
  10.  It gets a bit confused in non-Roman fonts with numbers not in the US Ascii 
  11.  number range.
  12.  Thanks to David Greenfield @ Dartmouth for the keyboard stuff.
  13.  
  14.  version d14 completed 1/11/89 
  15.  
  16.  d14: clean up code 
  17.  d13: all fields blank if any one is except binaries 
  18.  d12: fixed TEInit problem
  19.         add MultiFinder awareness
  20.         and scrap publication for DAs
  21.  
  22.  d11: allow up to 3 error strings 
  23.  d10: try one field ascii again 
  24.  d9: faster paste 
  25.  d8: add paste capability 
  26.  d7: add window location remembering 
  27.  
  28.  rewrite of old BaseConverter (source number7.c) started 1/2/90 
  29.  
  30.  To create BaseConverter in Symantec C++ 6.0:
  31.      Include this source with ANSI Small, MacTraps, and BaseConverter 1.1.rsrc. 
  32.      Project type is APPL with creator BACO (not registered),
  33.      MF partition size 100, and MF attributes = 5800 (all 3 settings chosen)
  34. */
  35.  
  36. /* Mac header files needed */
  37.  
  38. #include <QuickDraw.h>
  39. #include <Events.h>
  40. #include <Windows.h>
  41. #include <Menus.h>
  42. #include <Memory.h>
  43. #include <Resources.h>
  44. #include <Controls.h>
  45. #include <Dialogs.h>
  46. #include <Traps.h>
  47. #include <Script.h>
  48.  
  49.  
  50. /* C library headers needed */
  51. #include "stdio.h"
  52. #include "ctype.h"
  53. #include "string.h"
  54.  
  55. /* globals and constants */
  56.  
  57. /* menus */
  58.  
  59. #define deskMenuID 1
  60. #define fileMenuID 256
  61. #define editMenuID 257
  62. #define fontMenuID 258
  63. MenuHandle deskMenu,fileMenu,editMenu,fontMenu;
  64.  
  65.  
  66. /* dialog items */
  67.  
  68. #define kDecimal 1
  69. #define kOctal 2
  70. #define kHex 3
  71. #define kBinLoLSB 4
  72. #define kBinLoMSB 5
  73. #define kBinHiLSB 6
  74. #define kBinHiMSB 7
  75. #define kAscii 8
  76. #define kAsciiDump 9
  77. #define kErrorDisplay 10
  78. #define kLabels 11
  79.  
  80. /* misc other constants */
  81.  
  82. #define BS 8                            /* backspace key */
  83. #define TAB 9                            /* tab key */
  84. #define QUITKEY 113                        /* Q key */
  85. #define MINUS 45                        /* - */
  86. #define MAXLONGINT 2147483647.0
  87. #define MINLONGINT -2147483647.0
  88.  
  89. /* the dialog window */
  90.  
  91. DialogPtr BCDialog;                        /* pointer to it */
  92. #define BCDialogID 11050                /* resource ID of template */
  93.  
  94. char asciiText[4][16],asciiNums[4][16];    /* ascii dump strings */
  95.  
  96. char *conversion[3] = {"%ld","%lo","%lx"};    /* number conversion formats */
  97.  
  98. /* ascii chart abbreviations */
  99. char *ascii[] = {"NUL","SOH","STX","EXT","EOT","ENQ","ACK","BEL","BS ","HT ","LF ","VT ",
  100.                  "FF ","CR ","SO ","SI ","DLE","DC1","DC2","DC3","DC4","NAK","SYN","ETB",
  101.                  "CAN","EM ","SUB","ESC","FS ","GS ","RS ","US "};
  102.  
  103. short maxChar[] ={16,16,12,8,8,8,8,4};    /* maximum number of characters allowed 
  104.                                            for each dialog item */
  105.                                            
  106. QDProcs myProcs;                          /* replacement QuickDraw procs record */
  107.  
  108. short lastItemHit;                        /* remember last hit item here */
  109. long lastNum = -1;                /* remember last number value shown, init to -1 */
  110.  
  111. /* error handling */
  112.  
  113. char errorStr[4][64];              /* current error strings */
  114. short numErrors;                    /* current number of errors */
  115. Boolean outOfRange;                /* input is out of range for a long int */
  116. Boolean invalidChar;            /* input character is invalid for base */
  117. Boolean maxCharsExceeded;        /* too many characters typed */
  118. short pasteError;                    /* holds any error from paste operation */
  119. #define kPasteOK 0                /* paste error value: no error */
  120. #define kPasteTooLong 2            /* paste error value: too long to fit in field */
  121. #define kPasteInvalid 4            /* paste error value: invalid characters in stream */
  122.  
  123. /* event loop globals and constants */
  124.  
  125. Rect limitRect;                    /* drag limit area */
  126.  
  127. /* MultiFinder stuff */
  128.  
  129. #define App4Selector(eventPtr)     (*((unsigned char *) &(eventPtr)->message))
  130. /* top byte of message field is the selector */
  131.  
  132. #define SUSPEND_RESUME_SELECTOR        0x01
  133. /* selector of this value is suspend/resume */
  134.  
  135. #define SuspResIsResume(evtMessage)        ((evtMessage) & 0x00000001)
  136. /* low bit on, signifies resume */
  137.  
  138. #define SuspResIsSuspend(evtMessage)    (!SuspResIsResume(evtMessage))
  139. /* low bit off, signifies suspend */
  140.  
  141. #define ScrapDataHasChanged(evtMessage)     ((evtMessage) & 0x00000002)
  142. /* only valid for suspend/resume messages */
  143.  
  144. Boolean wneIsImplemented;            /* is WaitNextEvent implmented? */
  145. Boolean inForeground;                /* are we in MF foreground? */
  146. TEHandle theTEH;                    /* dialog te handle */
  147.  
  148. /* some prototypes */
  149.  
  150. Byte GetByte();
  151. Boolean maxCharacters();
  152. Boolean SelectionEmpty();
  153. pascal void DrawLabels ();
  154. pascal void AsciiDump ();
  155. pascal void ErrorDisplay ();
  156. pascal short MyStdTextMeas();
  157. pascal void MyStdText();
  158. pascal Boolean MyWordBreak();
  159. pascal void OutlineButton ();
  160. void BinaryConvert(char *s,long *n);
  161. void MakeBinary(long n,char *s,short fByte);
  162. void SyncKeyboard2Font(short fontID );
  163.  
  164.  
  165.  
  166. /* ======================== Event Handling ================ */
  167.  
  168. main()
  169. {   
  170.     
  171.     short windowCode;                            /* window event code */
  172.     Boolean mayBe;                            /* utility boolean */
  173.     EventRecord myEvent;                    /* the event record */
  174.     WindowPtr whichWindow;                    /* utility window ptr */
  175.     GrafPtr gp;                                /* utility graf ptr */
  176.     OSErr err;                                /* utility OS Err */
  177.     
  178.     
  179.     StdInits();                                /* start the application */
  180.     MyInits();
  181.     
  182.     /* run main event loop */
  183.     
  184.     while (1) {    
  185.                             
  186.         SetPort(BCDialog);                
  187.         CheckMenus();
  188.         
  189.         /* get the event */
  190.         
  191.         if (wneIsImplemented) {            /* get an event */
  192.             mayBe = WaitNextEvent(everyEvent,&myEvent,10L,NULL);
  193.         }
  194.         else {
  195.             SystemTask();
  196.             mayBe = GetNextEvent(everyEvent,&myEvent);
  197.         }
  198.         
  199.         /* process the event */
  200.         
  201.         if (IsDialogEvent(&myEvent)) 
  202.             DoDialogEvent(&myEvent);
  203.         else switch(myEvent.what) {            /* other events */
  204.             case mouseDown:
  205.                 windowCode = FindWindow(myEvent.where,&whichWindow);
  206.                 if ((whichWindow!=FrontWindow()) 
  207.                     &&(whichWindow!=NULL)) SelectWindow(whichWindow);
  208.                 switch(windowCode) {
  209.                     case inContent:
  210.                         break;
  211.                     case inMenuBar:
  212.                         DoMenu(MenuSelect(myEvent.where));
  213.                         break;
  214.                     case inSysWindow:
  215.                         SystemClick(&myEvent,whichWindow);
  216.                         break;
  217.                     case inGoAway:
  218.                         mayBe = TrackGoAway(whichWindow,myEvent.where);
  219.                         if (mayBe==TRUE) {
  220.                             DoExit();
  221.                         }
  222.                         break;
  223.                     case inDrag:
  224.                         DragWindow(whichWindow,myEvent.where,&limitRect);
  225.                         DrawGrowIcon(whichWindow);
  226.                         break;
  227.                     case inGrow:
  228.                         break;
  229.                 }
  230.             break;
  231.             case updateEvt:
  232.                 whichWindow = (WindowPtr)myEvent.message;
  233.                 GetPort(&gp);
  234.                 SetPort(whichWindow);
  235.                 BeginUpdate(whichWindow);
  236.                     DrawControls(whichWindow);
  237.                     DrawGrowIcon(whichWindow);
  238.                     EndUpdate(whichWindow);
  239.                 SetPort(gp);
  240.             break;
  241.             case keyDown:
  242.             break;
  243.             case activateEvt:
  244.                 if ((WindowPtr)myEvent.message==BCDialog) {
  245.                     if ( myEvent.modifiers & activeFlag ) 
  246.                         err = TEFromScrap();
  247.                     else {
  248.                         err = ZeroScrap();
  249.                         if (err==noErr)
  250.                             TEToScrap();
  251.                     }
  252.                 }
  253.             break;
  254.             case app4Evt:
  255.                 HandleApp4Evt(&myEvent);
  256.             break;
  257.         }
  258.     }
  259. }
  260.  
  261. /* process a dialog event */
  262.  
  263. DoDialogEvent(myEvent)
  264. EventRecord *myEvent;
  265. {            
  266.     short code,                                /* character code */
  267.         itemHit;                            /* dialog item chosen */
  268.     DialogPtr whichDialog;                    /* utility dialog ptr */
  269.     OSErr err;                                /* utility os error */
  270.     short ok;                                    /* dialog event status */
  271.     /* check for MF suspend/resume events */
  272.     
  273.     if (myEvent->what == app4Evt)  {
  274.         if (HandleApp4Evt(myEvent))
  275.             return;
  276.     }
  277.     
  278.     /* check for window activate events */
  279.     
  280.     else if (myEvent->what == activateEvt) {
  281.         if ((WindowPtr)myEvent->message==BCDialog) {
  282.             if ( myEvent->modifiers & activeFlag ) 
  283.                 err = TEFromScrap();                /* get global scrap */
  284.             else {
  285.                 err = ZeroScrap();                    /* publish our scrap */
  286.                 if (err==noErr)
  287.                     TEToScrap();
  288.             }
  289.         }
  290.     }
  291.  
  292.     /* Handle a key or mouse event */
  293.     
  294.     if ((myEvent->what==keyDown) || (myEvent->what==autoKey))  {
  295.         // Do this in case the user changed the keyboard
  296.         SyncKeyboard2Font((**theTEH).txFont);
  297.         code = BitAnd(myEvent->message,charCodeMask);  /* what keys was pressed? */
  298.             
  299.         /* check command keys */
  300.         if ((myEvent->modifiers & cmdKey) != 0) {
  301.             DoMenu(MenuKey(code));
  302.             ShowErrors();
  303.             return;
  304.         }
  305.         else {
  306.             ok = 1;                                    /* assume character is valid */
  307.             
  308.             /* filter invalid characters */
  309.             if ((code!=BS)&&(code!=TAB)) {
  310.                 if (lastItemHit<kAscii) {
  311.                     invalidChar = FALSE;
  312.                     ok = ValidChar(code,lastItemHit);
  313.                 }
  314.                 if (ok==1) {
  315.                     maxCharsExceeded = FALSE;
  316.                     ok = maxCharacters(lastItemHit);
  317.                 }
  318.                 if (!ok) {
  319.                     Str255 n;
  320.                     NumToString((long)code,n);
  321.                     SetWTitle(BCDialog,n);
  322.                     ShowErrors();
  323.                     return;
  324.                 }
  325.             }
  326.         }
  327.     }
  328.     
  329.     /* if character is valid or we got a mouseDown, process the event */
  330.     invalidChar = FALSE;
  331.     maxCharsExceeded = FALSE;
  332.     if (DialogSelect(myEvent,&whichDialog,&itemHit)) {
  333.         
  334.         // Some fonts make the text jump, so we do this to clean it up
  335.         Rect r = (**theTEH).viewRect;
  336.         InvalRect(&r);
  337.         if (whichDialog!=BCDialog) return;            /* what else can it be? */
  338.         pasteError = kPasteOK;
  339.         DoDialog(itemHit);
  340.         ShowErrors();
  341.     }
  342. }
  343.  
  344.  
  345. /* Handle the app4 event if and only if its a suspend/resume event */
  346. /* The only action we take is to convert the scrap to and from the
  347.    public scrap */
  348.  
  349. HandleApp4Evt(theEvent)
  350. EventRecord *theEvent;
  351. {
  352.     OSErr    err;
  353.     
  354.     if (App4Selector(theEvent) == SUSPEND_RESUME_SELECTOR) {
  355.         if SuspResIsSuspend(theEvent->message) {
  356.             inForeground = FALSE;
  357.             TEDeactivate(theTEH);
  358.             if (ScrapDataHasChanged(theEvent->message)) {
  359.                 err = ZeroScrap();
  360.                 err = TEToScrap();                    /* convert the scrap */
  361.             }
  362.         }
  363.         else {
  364.             inForeground = TRUE;
  365.             TEActivate(theTEH);
  366.             if (ScrapDataHasChanged(theEvent->message))
  367.                 err = TEFromScrap();                /* convert the scrap */
  368.         }
  369.         return 1;
  370.     }
  371.     return 0;
  372. }
  373.  
  374. /* ================== Initialization ===================== */
  375.  
  376. /* From Symantec C++ OSChecks.cp */
  377.  
  378. /******************************************************************************
  379.  TrapAvailable
  380.  
  381.      Check whether a certain trap exists on this machine. This function uses
  382.      the new method as per IM VI, p. 3-8.
  383.      
  384.  ******************************************************************************/
  385.  
  386. Boolean TrapAvailable( short theTrap)
  387. {
  388.     TrapType tType;
  389.     short    numToolBoxTraps;
  390.     
  391.                 // first determine the trap type
  392.                 
  393.     tType = (theTrap & 0x800) > 0 ? ToolTrap : OSTrap;
  394.     
  395.                 // next find out how many traps there are
  396.                 
  397.     if (NGetTrapAddress( _InitGraf, ToolTrap) == NGetTrapAddress( 0xAA6E, ToolTrap))
  398.         numToolBoxTraps = 0x200;
  399.     else
  400.         numToolBoxTraps = 0x400;
  401.     
  402.                 // check if the trap number is too big for the
  403.                 // current trap table
  404.                 
  405.     if (tType == ToolTrap)
  406.     {
  407.         theTrap &= 0x7FF;
  408.         if (theTrap >= numToolBoxTraps)
  409.             theTrap = _Unimplemented;
  410.     }
  411.     
  412.                 // the trap is implemented if its address is
  413.                 // different from the unimplemented trap
  414.                 
  415.     return (NGetTrapAddress( theTrap, tType) != 
  416.             NGetTrapAddress(_Unimplemented, ToolTrap));
  417. }
  418.  
  419. /******************************************************************************
  420.  WNEIsImplemented
  421.  
  422.      Check whether the WaitNextEvent is implemented or not
  423.  ******************************************************************************/
  424.  
  425. Boolean        WNEIsImplemented()
  426. {
  427.     SysEnvRec    theWorld;                /* System environment                */
  428.     
  429.     SysEnvirons(1, &theWorld);            /* Check environment                */
  430.     
  431.     if (theWorld.machineType < 0)         /* Old ROMs, definitely not present    */
  432.         return(false);
  433.         
  434.     else                                /* Check for WNE trap                */
  435.         return(TrapAvailable(_WaitNextEvent));
  436. }
  437.  
  438. /* standard Toolbox inits and start up */
  439.  
  440. StdInits()
  441. {    
  442.     InitGraf(&thePort);
  443.     InitFonts(); 
  444.     FlushEvents(everyEvent,0);
  445.     InitWindows();
  446.     InitMenus();
  447.     TEInit();
  448.     InitDialogs(NULL);
  449.     InitCursor();
  450.     MaxApplZone();
  451.     MoreMasters();
  452.     MoreMasters();
  453. }
  454.  
  455. /* Inits specific to this app */
  456.  
  457. MyInits()
  458. {
  459.     Handle iH;
  460.     short iType,i;
  461.     Rect box;
  462.     DialogPeek dp;
  463.     OSErr err;
  464.  
  465.     
  466.     /* prepare for MultiFinder */
  467.     
  468.     inForeground = TRUE;
  469.     wneIsImplemented = WNEIsImplemented();
  470.     
  471.     /* get our dialog template and create a window */
  472.     
  473.     BCDialog = GetNewDialog(BCDialogID,NULL,(WindowPtr)-1);
  474.     if (BCDialog==NULL) {
  475.         SysBeep(10);
  476.         DoExit();
  477.     }
  478.     
  479.  
  480.     /* set up the user items */
  481.     
  482.     GetDItem(BCDialog,kLabels,&iType,&iH,&box);
  483.     SetDItem(BCDialog, kLabels, userItem + itemDisable,
  484.          (Handle)DrawLabels, &box);
  485.     GetDItem(BCDialog,kAsciiDump,&iType,&iH,&box);
  486.     SetDItem(BCDialog, kAsciiDump, userItem + itemDisable,
  487.          (Handle)AsciiDump, &box);
  488.     GetDItem(BCDialog,kErrorDisplay,&iType,&iH,&box);
  489.     SetDItem(BCDialog, kErrorDisplay, userItem + itemDisable,
  490.          (Handle)ErrorDisplay, &box);
  491.     
  492.     /* override some graf procs for special measure and drawing */
  493.     
  494.     SetPort(BCDialog);
  495.     SetStdProcs(&myProcs);
  496.     myProcs.textProc    =    (QDPtr)MyStdText;
  497.     myProcs.txMeasProc    =    (QDPtr)MyStdTextMeas;
  498.     BCDialog->grafProcs = &myProcs;
  499.     
  500.     /* set our special word break procedure */
  501.     dp = (DialogPeek)BCDialog;
  502.     theTEH = dp->textH;
  503.     SetWordBreak(MyWordBreak,theTEH);
  504.     
  505.     /* import the public scrap */
  506.     err = TEFromScrap();
  507.     
  508.     /* create my menus */
  509.     setupmenus();
  510.  
  511.     /* set the window where it should be */
  512.     
  513.     PositionWindow();
  514.     SetFont();
  515.     
  516.     /* initialize some globals */
  517.     
  518.     lastItemHit = kDecimal;
  519.     numErrors = 0;
  520. }
  521.  
  522. /* position the window where it wants to be unless it is off screen */ 
  523.  
  524. PositionWindow()
  525. {
  526.     DialogTHndl dt;
  527.     RgnHandle grayRgn;
  528.     Rect myRect,testRect;
  529.     Point tl;
  530.     
  531.     /* get the dialog template  */
  532.     
  533.     dt = (DialogTHndl)GetResource('DLOG',BCDialogID);
  534.     if (dt==NULL) {
  535.         return;
  536.     }
  537.     
  538.     /* get the rectangle where the window was left last time */
  539.     
  540.     myRect = (**dt).boundsRect;
  541.     
  542.     /* if the topLeft of that rectangle is not within the current screen,
  543.        move the window to a sensible locations.  (This can only occur if the
  544.        copy of the app moves from a big screen system to a smaller screen system) */
  545.        
  546.     grayRgn = GetGrayRgn();
  547.     limitRect = (**grayRgn).rgnBBox;
  548.     tl.h = myRect.left;
  549.     tl.v = myRect.top;
  550.     if (PtInRect(tl,&limitRect)==FALSE) {   /* is off screen */
  551.         MoveWindow(BCDialog,54,78,FALSE);
  552.     }
  553.     
  554.     /* and show the window */
  555.     
  556.     ShowWindow(BCDialog);
  557. }
  558.  
  559. SetFont()
  560. {
  561.     StringHandle sh;
  562.     short f,i;
  563.     Str255 name1,name2;
  564.     
  565.     if (!fontMenu)
  566.         return;
  567.         
  568.     sh = GetString(1000);
  569.     if (sh) {
  570.         GetFNum(*sh,&f);
  571.         (**theTEH).txFont = f;
  572.         TextFont(f);
  573.         BlockMove(*sh,name2,255);
  574.         SyncKeyboard2Font(f);
  575.     }
  576.     else {
  577.         (**theTEH).txFont = systemFont;
  578.         TextFont(systemFont);
  579.         strcpy((char*)name2,(char*)"\pChicago");
  580.         SyncKeyboard2Font(systemFont);
  581.     }
  582.     TECalText(theTEH);
  583.     
  584.     for (i=1;i<CountMItems(fontMenu);i++) {
  585.         GetItem(fontMenu,i,name1);
  586.         if (EqualString(name1,name2,false,false))
  587.             CheckItem(fontMenu,i,true);
  588.     }
  589.     
  590. }
  591.  
  592. /* ====================== Menu Handling ================ */
  593.  
  594. /* create our menus */
  595.  
  596. setupmenus()
  597. {
  598.     char appletitle[2];
  599.  
  600.     /* desk accessories */
  601.      
  602.     appletitle[1] = appleMark;appletitle[0]=1;
  603.     deskMenu = NewMenu(deskMenuID,(StringPtr)appletitle);         
  604.     AppendMenu(deskMenu,"\pAbout Base Converter…;(-");
  605.     AddResMenu(deskMenu,'DRVR');
  606.     InsertMenu(deskMenu,0);
  607.     
  608.     /* file menu */
  609.     
  610.     fileMenu = NewMenu(fileMenuID,"\pFile");
  611.     AppendMenu(fileMenu,"\pQuit/Q");
  612.     InsertMenu(fileMenu,0);
  613.  
  614.     /* edit menu */
  615.     
  616.     editMenu = NewMenu(editMenuID,"\pEdit");
  617.     AppendMenu(editMenu,"\p(Can't Undo;(-;Cut /X;Copy /C;Paste /V;Clear");
  618.     InsertMenu(editMenu,0);
  619.     
  620.     
  621.     /* We only allow font changes if the TERecord of the dialog is not styled,
  622.        which it is not as of this release. */
  623.        
  624.     if ((**theTEH).txSize >= 0) {
  625.         /* font menu */
  626.         
  627.         fontMenu = NewMenu(fontMenuID,"\pFont");
  628.         AddResMenu(fontMenu,'FONT');
  629.         InsertMenu(fontMenu,0);
  630.     }
  631.     else
  632.         fontMenu = NULL;
  633.     
  634.     DrawMenuBar();
  635. }
  636.  
  637. /* process a menu event */
  638.  
  639. DoMenu(menuresult)
  640. /* handle menu commands */
  641. long menuresult;
  642. {
  643.     short menuid,itemnumber,i,itemHit,t;
  644.     char markchar;
  645.     Str255 name;
  646.     GrafPtr cp;
  647.     Rect r;
  648.             
  649.     menuid = HiWord(menuresult);
  650.     itemnumber = LoWord(menuresult);
  651.     switch (menuid) {
  652.     
  653.         /* DA's */
  654.         
  655.         case deskMenuID:
  656.             if (itemnumber==1) 
  657.                 DoAbout();
  658.             else {
  659.                 GetItem(deskMenu,itemnumber,name);
  660.                 GetPort(&cp);
  661.                 i = OpenDeskAcc(name);
  662.                 SetPort(cp);
  663.             }
  664.         break;
  665.         
  666.         /* file menu */
  667.         
  668.         case fileMenuID:
  669.             switch (itemnumber) {
  670.                 case 1: {
  671.                     DoExit();
  672.                    }              
  673.                 break;    
  674.             }
  675.         break;
  676.         
  677.         /* edit menu */
  678.         
  679.         case editMenuID:
  680.             if (!SystemEdit(itemnumber-1))     /* is it a DA? */
  681.             switch (itemnumber) {
  682.                 case 1:              
  683.                 break;
  684.                 case 3:
  685.                     DlgCut(BCDialog);
  686.                     r = (**theTEH).viewRect;
  687.                     EraseRect(&r);
  688.                     InvalRect(&r);
  689.                     ClearErrors();
  690.                 break;
  691.                 case 4:
  692.                     DlgCopy(BCDialog);
  693.                 break;
  694.                 case 5:    
  695.                     DoPaste();
  696.                 break;
  697.                 case 6:
  698.                     DlgDelete(BCDialog);
  699.                     ClearErrors();
  700.                 break;
  701.             }
  702.         break;
  703.         case fontMenuID:
  704.         {
  705.             
  706.             for (i=1;i<CountMItems(fontMenu);i++) {
  707.                 CheckItem(fontMenu,i,(i == itemnumber));
  708.             }
  709.             GetItem(fontMenu,itemnumber,name);
  710.             GetFNum(name,&i);
  711.             TEDeactivate(theTEH);
  712.             (**theTEH).txFont = i;
  713.             TextFont(i);
  714.             TECalText(theTEH);
  715.             TEActivate(theTEH);
  716.             SyncKeyboard2Font(i);
  717.             ClipRect(&BCDialog->portRect);
  718.             EraseRect(&BCDialog->portRect);
  719.             InvalRect(&BCDialog->portRect);            
  720.         }
  721.     }
  722.     
  723.     HiliteMenu(0);
  724. }
  725.  
  726. /* quit the program */
  727.  
  728. DoExit()
  729. {    
  730.     OSErr err;
  731.     
  732.     if (BCDialog!= NULL) {
  733.     
  734.         /* publish the scrap */
  735.         
  736.         err = ZeroScrap();
  737.         err = TEToScrap();
  738.         
  739.         /* save the window position */
  740.         RememberPosition();
  741.         RememberFont();
  742.         
  743.         /* clean up */
  744.         
  745.         DisposDialog(BCDialog);
  746.     }
  747.     ExitToShell();
  748. }
  749.  
  750. /* remember the current window position */
  751.  
  752. RememberPosition()
  753. {
  754.     Rect myRect;
  755.     Point corner;
  756.     DialogTHndl dt;
  757.     
  758.     /* get the current location */
  759.     SetPort(BCDialog);
  760.     myRect = BCDialog->portRect;
  761.     
  762.     /* change it to global coordinates */
  763.     corner.h = myRect.left;
  764.     corner.v = myRect.top;
  765.     LocalToGlobal(&corner);
  766.     myRect.left = corner.h;
  767.     myRect.top = corner.v;
  768.     corner.h = myRect.right;
  769.     corner.v = myRect.bottom;
  770.     LocalToGlobal(&corner);
  771.     myRect.right = corner.h;
  772.     myRect.bottom = corner.v;
  773.  
  774.     /* save location in the dialog template if we can */
  775.     dt = (DialogTHndl)GetResource('DLOG',BCDialogID);
  776.     if (dt==NULL) {
  777.         return;
  778.     }
  779.     (**dt).boundsRect = myRect;
  780.     ChangedResource((Handle)dt);
  781.     if (ResError()!=noErr) {                    /* volume is locked, can't do it */
  782.         return;
  783.     }
  784.     WriteResource((Handle)dt);
  785.     if (ResError()!=noErr) {
  786.         return;
  787.     }
  788. }
  789.  
  790. /* remember the current font */
  791.  
  792. RememberFont()
  793. {
  794.     StringHandle sh;
  795.     Str255 name;
  796.     
  797.     sh = GetString(1000);
  798.     if (sh != NULL) {
  799.         RmveResource((Handle)sh);
  800.     }
  801.     GetFontName((**theTEH).txFont,name);
  802.     sh = NewString(name);
  803.     AddResource((Handle)sh,'STR ',1000,"\pFont");
  804.     if (ResError()!=noErr) {                    /* volume is locked, can't do it */
  805.         return;
  806.     }
  807.     WriteResource((Handle)sh);
  808. }
  809.  
  810. /* show the about box */
  811.  
  812. DoAbout()
  813. {
  814.     #define ABOUTDIALOG 11051
  815.     #define kOKBUTTON 1
  816.     #define kOUTLINER 2
  817.  
  818.     DialogPtr theDialog;
  819.     WindowPtr tempport;
  820.     short    itemhit,itemType;
  821.     Handle    itemHandle;
  822.     Rect    itemBox;
  823.     Boolean done;
  824.         
  825.     /* get the dialog box */
  826.     theDialog = GetNewDialog(ABOUTDIALOG, 0L,(WindowPtr) -1);
  827.     if (theDialog == NULL) {
  828.         SysBeep(1);
  829.         return;
  830.     }
  831.         
  832.     InitCursor();
  833.     
  834.     /* install the default outline */
  835.     GetDItem(theDialog,kOKBUTTON,&itemType,&itemHandle,&itemBox);
  836.     SetDItem(theDialog, kOUTLINER, userItem + itemDisable,
  837.          (Handle)OutlineButton, &itemBox);
  838.  
  839.     /* pose the dialog */
  840.     ShowWindow(theDialog);
  841.     
  842.     /* wait for button hit */
  843.     done = FALSE;
  844.     while (!done) {
  845.         ModalDialog(0L,&itemhit);
  846.         if (itemhit==kOKBUTTON)
  847.             done = TRUE;
  848.     }
  849.  
  850.     DisposDialog(theDialog);
  851.     return TRUE;
  852. }
  853.  
  854. /* Handle a paste operation our way: scan all characters on the scrap.
  855.    Each valid one that will fit is moved to a buffer.  Error states
  856.    are set for invalid characters and when the length gets too long.
  857.    The buffer of valid characters is then inserted. */
  858.  
  859. DoPaste()
  860. {
  861.     Handle scrapH;
  862.     long len,offset;
  863.     short i,pos;
  864.     char c;
  865.     char buff[32];
  866.     TEHandle theTEH;
  867.     DialogPeek dp;
  868.     short    iType;
  869.     Handle    iH;
  870.     Rect    box;
  871.     short tLen,sLen,room;
  872.     Str255 temp;
  873.     
  874.     /* get the TE handle */
  875.     
  876.     dp = (DialogPeek)BCDialog;
  877.     theTEH = dp->textH;
  878.  
  879.     /* init the error level to ok */
  880.     
  881.     pasteError = kPasteOK;
  882.     
  883.     /* init the buffer */
  884.     buff[0] = pos = 0;
  885.     
  886.     /* limit the input to 32 chars because no field can hold that much anyway */
  887.     
  888.     len = TEGetScrapLen();
  889.     if (len>32) {
  890.         len = 32;
  891.         pasteError = kPasteTooLong;
  892.     }
  893.     
  894.     /* if there is somethig to paste */
  895.      if (len>0L) {
  896.          
  897.          /* get the scrap */
  898.          
  899.         scrapH = TEScrapHandle();
  900.         HLock(scrapH);
  901.         
  902.         /* process each character in it */
  903.         
  904.          for (i=0;i<len;i++) {
  905.             c = *(*scrapH+i);
  906.             if (ValidChar(c,lastItemHit)) {
  907.                 buff[pos] = c;
  908.                 buff[pos+1] = 0;
  909.                 pos++;
  910.             }
  911.             else 
  912.                 pasteError = kPasteInvalid;
  913.         }
  914.         HUnlock(scrapH);
  915.         
  916.         /* see how much of it will fit */
  917.         
  918.         GetDItem(BCDialog,lastItemHit,&iType,&iH,&box);
  919.         GetIText(iH,temp);
  920.         tLen = temp[0];                                     /* have this much now */
  921.         sLen = (**theTEH).selEnd - (**theTEH).selStart;      /* selection is this long */
  922.         room = maxChar[lastItemHit-1] - tLen + sLen;          /* can fit this much */
  923.         if (pos > room) {
  924.             pos = room;
  925.             pasteError = kPasteTooLong;
  926.         }
  927.         
  928.         /* delete the selection and insert the processed buffer */
  929.         
  930.         TEDelete(theTEH);
  931.         TEInsert(&buff,(long)pos,theTEH);
  932.         
  933.         /* update all other fields */
  934.         
  935.         DoDialog(lastItemHit);
  936.     }
  937.     
  938.     /* report any errors */
  939.     
  940.     ShowErrors();
  941. }
  942.  
  943. /* Enable/Disable menus according to conditions. */
  944.  
  945. CheckMenus()
  946. {
  947.     long len,offset;
  948.     Boolean weAreInFront;
  949.     
  950.     weAreInFront = (FrontWindow()==BCDialog);
  951.         
  952.     /* cut/copy/clear */
  953.     
  954.     if (SelectionEmpty()&&(weAreInFront)) {
  955.         DisableItem(editMenu,3);
  956.         DisableItem(editMenu,4);
  957.         DisableItem(editMenu,6);
  958.     }
  959.     else {
  960.             EnableItem(editMenu,3);
  961.         EnableItem(editMenu,4);
  962.         EnableItem(editMenu,6);
  963.     }
  964.     
  965.     /* paste */
  966.     
  967.     len = TEGetScrapLen();
  968.     if ((len==0L)&&(weAreInFront))
  969.         DisableItem(editMenu,5);
  970.     else 
  971.         EnableItem(editMenu,5); 
  972.     
  973. }
  974.  
  975.  
  976. /* ================== Dialog Handling ==================== */
  977.  
  978. /* handle dialog actions */
  979.  
  980. DoDialog(itemHit)
  981. short itemHit;
  982. {
  983.     long num,num1,num2,num3,num4;
  984.     Str255 temp,temp2;
  985.     char temp3[32];
  986.     Handle iH;
  987.     short iType,i,j;
  988.     Rect box;
  989.     GrafPtr savePort;
  990.     double fNum;
  991.     Boolean emptyText = FALSE;
  992.     
  993.     outOfRange = FALSE;
  994.     lastItemHit = itemHit;
  995.     
  996.     /* get source of number */
  997.     
  998.     GetDItem(BCDialog,itemHit,&iType,&iH,&box);
  999.     GetIText(iH,temp);
  1000.     
  1001.     if (temp[0] == 0) {
  1002.         if ((itemHit < kBinLoLSB)||(itemHit > kBinHiMSB))
  1003.             emptyText = TRUE;
  1004.     }
  1005.     if (EqualString(temp,"\p-",true,true)) {    /* special case of just a '-' */
  1006.         emptyText = TRUE;
  1007.         temp[0] = 0;
  1008.     }
  1009.         
  1010.     if (!emptyText) {    
  1011.         /* convert the target field first */
  1012.         
  1013.         switch(itemHit) {
  1014.             case kDecimal: {
  1015.                 PtoCstr(temp);
  1016.                 sscanf((char *)temp,"%lf",&fNum);
  1017.                 if ((fNum>MAXLONGINT)||(fNum<MINLONGINT)) {        /* out of range */
  1018.                     ClearAllFields(kDecimal);
  1019.                     outOfRange = TRUE;
  1020.                     lastNum = -1;
  1021.                     return;
  1022.                 }
  1023.                 sscanf((char *)temp,"%ld",&num);
  1024.                 CtoPstr((char*)temp);
  1025.                 break;    
  1026.             }
  1027.         
  1028.             case kOctal: {
  1029.                 PtoCstr(temp);
  1030.                 sscanf((char *)temp,"%lo",&num);
  1031.                 sprintf((char *)temp2,"%lo",num);
  1032.                 strcpy(temp3,(char *)temp);
  1033.                 StripLeadingZeros(temp3);
  1034.                 if (strcmp((char *)temp2,"0")==0)
  1035.                     temp2[0] = 0;
  1036.                 if (strcmp((char *)temp3,(char *)temp2)!=0) {                    /* out of range */
  1037.                     ClearAllFields(kOctal);
  1038.                     outOfRange = TRUE;
  1039.                     lastNum = -1;
  1040.                     return;
  1041.                 }
  1042.                 CtoPstr((char*)temp);
  1043.                 break;
  1044.             }
  1045.             
  1046.             case kHex: {
  1047.                 PtoCstr(temp);
  1048.                 sscanf((char *)temp,"%lx",&num);
  1049.                 sprintf((char *)temp2,"%lx",num);
  1050.                 strcpy(temp3,(char *)temp);
  1051.                 StripLeadingZeros(temp3);
  1052.                 if (strcmp((char *)temp2,"0")==0)
  1053.                     temp2[0] = 0;
  1054.                 ucase(temp3);
  1055.                 ucase((char*)temp2);
  1056.                 if (strcmp((char *)temp3,(char *)temp2)!=0) {                    /* out of range */
  1057.                     ClearAllFields(kHex);
  1058.                     outOfRange = TRUE;
  1059.                     lastNum = -1;
  1060.                     return;
  1061.                 }
  1062.                 ucase((char*)temp);
  1063.                 CtoPstr((char*)temp);
  1064.                 GetDItem(BCDialog,kHex,&iType,&iH,&box); 
  1065.                 SetIText(iH,temp);
  1066.                 break;
  1067.             }
  1068.             
  1069.             case kBinHiMSB: {
  1070.                 PtoCstr(temp);
  1071.                 BinaryConvert((char*)temp,&num1);                      /* num1 has MSB of hi word */
  1072.                 GetDItem(BCDialog,kBinHiLSB,&iType,&iH,&box);   /* get LSB of hi word */
  1073.                 GetIText(iH,temp);
  1074.                 PtoCstr(temp);
  1075.                 BinaryConvert((char*)temp,&num2);
  1076.                 GetDItem(BCDialog,kBinLoMSB,&iType,&iH,&box);   /* get MSB of low word */
  1077.                 GetIText(iH,temp);
  1078.                 PtoCstr(temp);
  1079.                 BinaryConvert((char*)temp,&num3);
  1080.                 GetDItem(BCDialog,kBinLoLSB,&iType,&iH,&box);   /* get LSB of lo word */
  1081.                 GetIText(iH,temp);
  1082.                 PtoCstr(temp);
  1083.                 BinaryConvert((char*)temp,&num4);
  1084.                 num = (num1<<24)+(num2<<16)+(num3<<8)+num4;
  1085.                 break;
  1086.             }
  1087.             case kBinHiLSB: {
  1088.                 PtoCstr(temp);
  1089.                 BinaryConvert((char*)temp,&num2);                      /* num2 has LSB of hi word */
  1090.                 GetDItem(BCDialog,kBinHiMSB,&iType,&iH,&box);   /* get MSB of hi word */
  1091.                 GetIText(iH,temp);
  1092.                 PtoCstr(temp);
  1093.                 BinaryConvert((char*)temp,&num1);
  1094.                 GetDItem(BCDialog,kBinLoMSB,&iType,&iH,&box);   /* get MSB of low word */
  1095.                 GetIText(iH,temp);
  1096.                 PtoCstr(temp);
  1097.                 BinaryConvert((char*)temp,&num3);
  1098.                 GetDItem(BCDialog,kBinLoLSB,&iType,&iH,&box);   /* get LSB of lo word */
  1099.                 GetIText(iH,temp);
  1100.                 PtoCstr(temp);
  1101.                 BinaryConvert((char*)temp,&num4);
  1102.                 num = (num1<<24)+(num2<<16)+(num3<<8)+num4;
  1103.                 break;
  1104.             }
  1105.             case kBinLoMSB: {
  1106.                 PtoCstr(temp);
  1107.                 BinaryConvert((char*)temp,&num3);                      /* num3 has MSB of lo word */
  1108.                 GetDItem(BCDialog,kBinHiMSB,&iType,&iH,&box);   /* get MSB of hi word */
  1109.                 GetIText(iH,temp);
  1110.                 PtoCstr(temp);
  1111.                 BinaryConvert((char*)temp,&num1);
  1112.                 GetDItem(BCDialog,kBinHiLSB,&iType,&iH,&box);   /* get LSB of hi word */
  1113.                 GetIText(iH,temp);
  1114.                 PtoCstr(temp);
  1115.                 BinaryConvert((char*)temp,&num2);
  1116.                 GetDItem(BCDialog,kBinLoLSB,&iType,&iH,&box);   /* get LSB of lo word */
  1117.                 GetIText(iH,temp);
  1118.                 PtoCstr(temp);
  1119.                 BinaryConvert((char*)temp,&num4);
  1120.                 num = (num1<<24)+(num2<<16)+(num3<<8)+num4;
  1121.                 break;
  1122.             }
  1123.             case kBinLoLSB: {
  1124.                 PtoCstr(temp);
  1125.                 BinaryConvert((char*)temp,&num4);                      /* num4 has LSB of lo word */
  1126.                 GetDItem(BCDialog,kBinHiMSB,&iType,&iH,&box);   /* get MSB of hi word */
  1127.                 GetIText(iH,temp);
  1128.                 PtoCstr(temp);
  1129.                 BinaryConvert((char*)temp,&num1);
  1130.                 GetDItem(BCDialog,kBinHiLSB,&iType,&iH,&box);   /* get LSB of hi word */
  1131.                 GetIText(iH,temp);
  1132.                 PtoCstr(temp);
  1133.                 BinaryConvert((char*)temp,&num2);
  1134.                 GetDItem(BCDialog,kBinLoMSB,&iType,&iH,&box);   /* get MSB of lo word */
  1135.                 GetIText(iH,temp);
  1136.                 PtoCstr(temp);
  1137.                 BinaryConvert((char*)temp,&num3);
  1138.                 num = (num1<<24)+(num2<<16)+(num3<<8)+num4;
  1139.                 break;
  1140.             }
  1141.             
  1142.             case kAscii: {
  1143.                 /* make a number from the bytes of the current string, but
  1144.                    shift them all to the right */
  1145.                 
  1146.                 num1 = num2 = num3 = num4 = 0;
  1147.                 
  1148.                 if (temp[0] > 0 )  
  1149.                     num1 = temp[temp[0]];
  1150.                 if (temp[0] > 1  ) 
  1151.                     num2 = temp[temp[0]-1];
  1152.                 if (temp[0] > 2  ) 
  1153.                     num3 = temp[temp[0]-2];
  1154.                 if (temp[0] > 3  ) 
  1155.                     num4 = temp[temp[0]-3];
  1156.               
  1157.                 /* assemble a new number from that */
  1158.                 num = num1 + (num2<<8) + (num3<<16) + (num4<<24);
  1159.                 break;
  1160.             }
  1161.         } /* end of target conversion switch */
  1162.     }     
  1163.     
  1164.     /* now reformat to destinations */    
  1165.     
  1166.     if (num==lastNum) return;
  1167.         
  1168.     if (itemHit<kBinLoLSB)  
  1169.         sscanf((char *)temp,(char *)conversion[itemHit-1],&num);
  1170.     
  1171.     for (i=1;i<kBinLoLSB;i++) {
  1172.         if (i!=itemHit) {
  1173.             if (!emptyText) {
  1174.                 sprintf((char *)temp,(char *)conversion[i-1],num);
  1175.                 ucase((char *)temp); // to get hex characters in upper case
  1176.                 CtoPstr((char *)temp);
  1177.             }
  1178.             GetDItem(BCDialog,i,&iType,&iH,&box);
  1179.             SetIText(iH,temp);
  1180.         }
  1181.     }
  1182.     
  1183.     if (itemHit!=kBinHiMSB) {
  1184.         GetDItem(BCDialog,kBinHiMSB,&iType,&iH,&box);   /* MSB of Hi Word */
  1185.         if (!emptyText) {
  1186.             MakeBinary(num,(char*)temp,3);
  1187.             CtoPstr((char *)temp);
  1188.         }
  1189.         SetIText(iH,temp);
  1190.     }
  1191.     if (itemHit!=kBinHiLSB) {
  1192.         if (!emptyText) {
  1193.             MakeBinary(num,(char*)temp,2);
  1194.             CtoPstr((char *)temp);
  1195.         }
  1196.         GetDItem(BCDialog,kBinHiLSB,&iType,&iH,&box);   /* LSB of Hi Word */
  1197.         SetIText(iH,temp);
  1198.     }
  1199.     if (itemHit!=kBinLoMSB) {
  1200.         if (!emptyText) {
  1201.             MakeBinary(num,(char*)temp,1);
  1202.             CtoPstr((char *)temp);
  1203.         }
  1204.         GetDItem(BCDialog,kBinLoMSB,&iType,&iH,&box);  /* MSB of Lo Word */
  1205.         SetIText(iH,temp);
  1206.     }
  1207.     if (itemHit!=kBinLoLSB) {
  1208.         if (!emptyText) {
  1209.             MakeBinary(num,(char*)temp,0);
  1210.             CtoPstr((char *)temp);
  1211.         }
  1212.         GetDItem(BCDialog,kBinLoLSB,&iType,&iH,&box);  /* LSB of Low Word */
  1213.         SetIText(iH,temp);
  1214.     }
  1215.  
  1216.     if (itemHit!=kAscii) {
  1217.         if (!emptyText) {
  1218.             for (i=1;i<5;i++) {
  1219.                 temp[i] = GetByte(num,5-i);
  1220.                 if (temp[i]==13) temp[i] = 255;   /* to avoid cr wraps */
  1221.             }
  1222.             temp[0] = 4;
  1223.             
  1224.             /* update text display in ascii box */
  1225.         }
  1226.         GetDItem(BCDialog,kAscii,&iType,&iH,&box);
  1227.         SetIText(iH,temp);
  1228.     }    
  1229.     
  1230.     /* show ascii dump display */
  1231.     if (num!=lastNum) {
  1232.         AsciiConvert(num,emptyText);
  1233.         /* force redraw of ascii dump area */
  1234.         GetPort(&savePort);
  1235.         SetPort(BCDialog);
  1236.         GetDItem(BCDialog,kAsciiDump,&iType,&iH,&box);
  1237.         InvalRect(&box);
  1238.         SetPort(savePort);
  1239.     }
  1240.     
  1241.     lastNum = num;
  1242. }
  1243.  
  1244. /* see if a character is valid for a given type */
  1245.  
  1246. ValidChar(c,type)
  1247. char c;
  1248. short type;
  1249. {
  1250.     short i;
  1251.     char *cp;
  1252.     Boolean badChar = FALSE;
  1253.     
  1254.     c = (char)toupper(c);
  1255.     switch (type) {
  1256.         case kDecimal:                        /* 0-9 */
  1257.            if (c!=MINUS) {
  1258.                    if (c<48) badChar = TRUE;
  1259.                    else if (c>57) badChar = TRUE;
  1260.                }
  1261.         break;
  1262.         case kOctal:                        /* 0-7 */
  1263.             if (c<48) badChar = TRUE;
  1264.             else if (c>55) badChar = TRUE;
  1265.         break;
  1266.         case kHex:                        /* 0-9, ABCDEF */
  1267.             if (c<48) badChar = TRUE;
  1268.             else {
  1269.                 cp = strchr((char*)"ABCDEF",(short)c);
  1270.                 if ((c>57)&&(cp==NULL)) badChar = TRUE;
  1271.             }
  1272.         break;
  1273.         case kAscii:
  1274.             return 1;                 /* any character is ok */
  1275.         break;
  1276.         case kBinLoLSB:                /* 0 and 1 only */
  1277.         case kBinHiLSB:
  1278.         case kBinLoMSB:
  1279.         case kBinHiMSB:
  1280.             if ((c<48)||(c>49)) badChar = TRUE;
  1281.         break;
  1282.     }
  1283.     if (badChar) {
  1284.         invalidChar = TRUE;
  1285.         return 0;
  1286.     }
  1287.     return 1;
  1288. }
  1289.  
  1290.  
  1291. /* report whether or not a given type already has the maximum number
  1292.    of characters. */
  1293.    
  1294. Boolean maxCharacters(type)
  1295. short type;
  1296. {    
  1297.     Handle iH;
  1298.     short iType,i;
  1299.     Rect box;
  1300.     Str255 temp;
  1301.     
  1302.     maxCharsExceeded = FALSE;
  1303.     
  1304.     /* see how many there are */
  1305.     
  1306.     GetDItem(BCDialog,type,&iType,&iH,&box);
  1307.     GetIText(iH,temp);
  1308.     
  1309.     /* check against the limit */
  1310.     
  1311.     if (temp[0]<maxChar[type-1])                 /* still room for more */
  1312.         return 1;
  1313.     
  1314.     if (!SelectionEmpty())    /* field is full, but there is room in the selection */
  1315.         return 1;
  1316.         
  1317.     /* no more room */
  1318.     SysBeep(0);
  1319.     maxCharsExceeded = TRUE;
  1320.     return 0;    
  1321. }
  1322.  
  1323. /* convert a string of 0s and 1s into a number equivalent to
  1324.    the binary representation of the 01 pattern */
  1325.    
  1326. void BinaryConvert(char *s,long *n)
  1327. {
  1328.     short i,j,len;
  1329.     long temp,x;
  1330.     
  1331.     temp = 0;
  1332.     len = strlen(s);
  1333.     j = 0;
  1334.     for (i=0;i<len;i++) {
  1335.         x = (long)(len-i-1);
  1336.         if (s[i]==49) temp = temp+(1<<x);
  1337.     }
  1338.     *n = temp;
  1339. }
  1340.  
  1341. /* convert a long to 4 characters into two representations:
  1342.    a string of ascii chart symbols and a string of decimal byte values. */
  1343.    
  1344. AsciiConvert(num,empty)
  1345. long num;
  1346. Boolean empty;
  1347. {
  1348.     short i,len;
  1349.     Byte c;
  1350.     Str255 numStr;
  1351.     
  1352.     /* init the strings */
  1353.     
  1354.     for (i=0;i<4;i++) {
  1355.         strcpy(asciiText[i],"");
  1356.         strcpy(asciiNums[i],"");
  1357.     }
  1358.     if (empty) return;            /* no text to represent */
  1359.     
  1360.     
  1361.     /* convert */
  1362.     
  1363.     for (i=0;i<4;i++) {
  1364.         c = GetByte(num,4-i);
  1365.         if (c<32) 
  1366.             strcat(asciiText[i],ascii[c]);
  1367.         else if (c==127)
  1368.                strcat(asciiText[i],"DEL");
  1369.         else {
  1370.             len = strlen(asciiText[i]);
  1371.             asciiText[i][len] = c;
  1372.             asciiText[i][len+1] = 0;
  1373.         }
  1374.         strcat(asciiText[i]," ");
  1375.         NumToString((long)c,numStr);
  1376.         PtoCstr(numStr);
  1377.         strcat(asciiNums[i],(char *)numStr);
  1378.         strcat(asciiNums[i],"  ");
  1379.         CtoPstr((char*)asciiText[i]);
  1380.         CtoPstr((char*)asciiNums[i]);
  1381.     }
  1382. }
  1383.  
  1384. /* given a long number and which byte to format, create a string that
  1385.    holds a binary representation of the number. */
  1386.    
  1387. void MakeBinary(long n,char *s,short fByte)
  1388. {
  1389.     short i,word;
  1390.     long test,temp;
  1391.     
  1392.     if (fByte > 1)                       /* use hi word */
  1393.         word = HiWord(n);
  1394.     else                                /* use lo word */
  1395.         word = LoWord(n);
  1396.     if ((fByte==1)||(fByte==3)) 
  1397.         temp = word>>8;                    /* get hi byte of the word */
  1398.     else {
  1399.         temp = word << 8;                /* get low byte of the word */
  1400.         temp = temp >> 8;
  1401.     }
  1402.     
  1403.     /* convert to pattern of 0's and 1's */
  1404.     for (i=7;i>-1;i--){
  1405.         test = 1<<i;
  1406.         if (temp&test) s[7-i] = 49;
  1407.         else s[7-i] = 48;
  1408.     }
  1409.     s[8] = 0;
  1410. }
  1411.  
  1412. /* is the current selection empty? */
  1413.  
  1414. Boolean SelectionEmpty()
  1415. {
  1416.     TEHandle theTEH;
  1417.     DialogPeek dp;
  1418.     
  1419.     dp = (DialogPeek)BCDialog;
  1420.     theTEH = dp->textH;
  1421.     return ((**theTEH).selStart==(**theTEH).selEnd);
  1422. }
  1423.  
  1424. /* erase contents of all fields except one */
  1425.  
  1426. ClearAllFields(except)
  1427. short except;
  1428. {
  1429.     short i;
  1430.     Handle iH;
  1431.     short iType;
  1432.     Rect box;
  1433.     GrafPtr savePort;
  1434.     
  1435.     for (i=1;i<kAsciiDump;i++) {
  1436.         if (i!=except) {
  1437.             GetDItem(BCDialog,i,&iType,&iH,&box);
  1438.             SetIText(iH,"\p");
  1439.         }
  1440.     }
  1441.     for (i=0;i<4;i++) {
  1442.         asciiText[i][0] = 0;
  1443.         asciiNums[i][0] = 0;
  1444.     }
  1445.     
  1446.     /* and force redraw of the ascii dump area */
  1447.     
  1448.     GetDItem(BCDialog,kAsciiDump,&iType,&iH,&box);
  1449.     GetPort(&savePort);
  1450.     SetPort(BCDialog);
  1451.     InvalRect(&box);
  1452.     SetPort(savePort);
  1453. }
  1454.  
  1455. /* ================ Error reporting ================= */
  1456.  
  1457. /* Build error strings and force a redraw of the errors display area. */
  1458.  
  1459. ShowErrors()
  1460. {
  1461.     GrafPtr savePort;
  1462.     short    iType;
  1463.     Handle    iH;
  1464.     Rect    box;
  1465.  
  1466.     numErrors = 0;
  1467.     if (outOfRange)
  1468.             AddError("Out of range for a long integer.");
  1469.     if (maxCharsExceeded)
  1470.             AddError("No more characters allowed here.");
  1471.     if (pasteError == kPasteInvalid)
  1472.             AddError("Some paste characters invalid for this base.");
  1473.     else if (invalidChar)
  1474.             AddError("Invalid character for this base.");
  1475.     if (pasteError == kPasteTooLong)
  1476.                 AddError("Paste text too long.");
  1477.     GetPort(&savePort);
  1478.     SetPort(BCDialog);
  1479.     GetDItem(BCDialog,kErrorDisplay,&iType,&iH,&box);
  1480.     InvalRect(&box);
  1481.     SetPort(savePort);
  1482. }
  1483.  
  1484. /* add an error to the error string array */
  1485.  
  1486. AddError(s)
  1487. char *s;
  1488. {
  1489.     numErrors++;
  1490.     if (numErrors>3) {
  1491.         DebugStr("\ptoo many errors");
  1492.         return;
  1493.     }
  1494.     strcpy(errorStr[numErrors-1],s);
  1495. }
  1496.  
  1497. /* clear all error flags */
  1498.  
  1499. ClearErrors()
  1500. {
  1501.     outOfRange = FALSE;
  1502.     invalidChar = FALSE;
  1503.     maxCharsExceeded = FALSE;
  1504.     pasteError = kPasteOK;
  1505.     ShowErrors();
  1506. }
  1507.  
  1508. /* ================ utility routines ================= */
  1509.  
  1510. /* remove any leading zeros (ascii48) */
  1511.  
  1512. StripLeadingZeros(s)
  1513. char *s;
  1514. {
  1515.     char s1[32];
  1516.     short i,len = 0;
  1517.     Boolean stripOn = TRUE;
  1518.     
  1519.     for (i=0;i<strlen(s),len<31;i++) {
  1520.         if ((s[i] != 48)||(!stripOn)) {
  1521.             s1[len] = s[i];
  1522.             len++;
  1523.             s1[len] = 0;
  1524.             stripOn = FALSE;
  1525.         }
  1526.     }
  1527.     strcpy(s,s1);
  1528. }
  1529.  
  1530. /* change a string to all uppser case */
  1531.  
  1532. ucase(s)
  1533. char *s;
  1534. {
  1535.     while (*s!=0) {
  1536.         *s = toupper((short)*s);
  1537.         s++;
  1538.     }
  1539. }
  1540.  
  1541. /* get a specified byte from a long int */
  1542.  
  1543. Byte GetByte(n,b)
  1544. long n;
  1545. short b;
  1546. {
  1547.     Byte it;
  1548.     short word;
  1549.     
  1550.     switch (b) {
  1551.         case 1:                            /* LSB of lo word */
  1552.             word = LoWord(n);
  1553.             it = word&255;
  1554.         break;
  1555.         case 2:                            /* MSB of lo word */
  1556.             word = LoWord(n);
  1557.             it = word>>8;
  1558.         break;
  1559.         case 3:                            /* LSB of hi word */
  1560.             word = HiWord(n);
  1561.             it = word&255;
  1562.         break;
  1563.         case 4:                            /* MSB of hi word */
  1564.             word = HiWord(n);
  1565.             it = word>>8;
  1566.         break;
  1567.     }
  1568.     return it;
  1569. }
  1570. /* ================ call back routines =============== */
  1571.  
  1572. /* ---------------- dialog user items ---------------- */
  1573.  
  1574. /* Dialog user item that draws the labels in the system font */
  1575.  
  1576. pascal void DrawLabels (myWindow,itemNo)
  1577. WindowPtr myWindow;
  1578. short itemNo;
  1579. {
  1580.     short iType,i;
  1581.     Handle iHandle;
  1582.     Rect iBox;
  1583.     short saveFont,saveSize;
  1584.     
  1585.     /* get the rectangle for this item and erase it */
  1586.     GetDItem(myWindow, itemNo, &iType, &iHandle, &iBox);
  1587.     EraseRect(&iBox);
  1588.     
  1589.     /* save the font in use */
  1590.     saveFont = myWindow->txFont;
  1591.     saveSize = myWindow->txSize;
  1592.     
  1593.     /* set a smaller one */
  1594.     TextFont(systemFont);
  1595.     TextSize(12);
  1596.     
  1597.     /* draw the text */
  1598.     MoveTo(iBox.left+6,iBox.top + 16);
  1599.     DrawString("\pDecimal");
  1600.     
  1601.     MoveTo(iBox.left+24,iBox.top + 40);
  1602.     DrawString("\pOctal");
  1603.     
  1604.     MoveTo(iBox.left+33,iBox.top + 65);
  1605.     DrawString("\pHex");
  1606.     
  1607.     MoveTo(iBox.left+16,iBox.top + 91);
  1608.     DrawString("\pBinary");
  1609.     
  1610.     MoveTo(iBox.left+27,iBox.top + 141);
  1611.     DrawString("\pAscii");
  1612.     
  1613.     /* reset font */
  1614.     TextFont(saveFont);
  1615.     TextSize(saveSize);
  1616. }
  1617.  
  1618. /* Dialog user item that displays the ascii field in alternate forms */
  1619.  
  1620. pascal void AsciiDump (myWindow,itemNo)
  1621. WindowPtr myWindow;
  1622. short itemNo;
  1623. {
  1624.     short iType,i;
  1625.     Handle iHandle;
  1626.     Rect iBox;
  1627.     short saveFont,saveSize;
  1628.     
  1629.     /* get the rectangle for this item and erase it */
  1630.     GetDItem(myWindow, itemNo, &iType, &iHandle, &iBox);
  1631.     EraseRect(&iBox);
  1632.     
  1633.     /* save the font in use */
  1634.     saveFont = myWindow->txFont;
  1635.     saveSize = myWindow->txSize;
  1636.     
  1637.     /* set a smaller one */
  1638.     TextFont(geneva);
  1639.     TextSize(9);
  1640.     
  1641.     /* draw the text */
  1642.     for (i=0;i<4;i++) {
  1643.         MoveTo(iBox.left+5+(i*22),iBox.top + 8);
  1644.         DrawString((StringPtr)asciiNums[i]);
  1645.         MoveTo(iBox.left+5+(i*22),iBox.top + 20);
  1646.         DrawString((StringPtr)asciiText[i]);
  1647.     }
  1648.     
  1649.     /* reset font */
  1650.     TextFont(saveFont);
  1651.     TextSize(saveSize);
  1652. }
  1653.  
  1654. /* display any error messages in small type at bottom of window */
  1655.  
  1656. pascal void ErrorDisplay (myWindow,itemNo)
  1657. WindowPtr myWindow;
  1658. short itemNo;
  1659. {
  1660.     short iType,i;
  1661.     Handle iHandle;
  1662.     Rect iBox;
  1663.     short saveFont,saveSize,width,center;
  1664.     
  1665.     /* get the rectangle for this item and erase it */
  1666.     GetDItem(myWindow, itemNo, &iType, &iHandle, &iBox);
  1667.     EraseRect(&iBox);
  1668.     
  1669.     /* if we have errors, draw them in a small font */
  1670.     if (numErrors!=0) {
  1671.         saveFont = myWindow->txFont;
  1672.         saveSize = myWindow->txSize;
  1673.         TextFont(geneva);
  1674.         TextSize(9);
  1675.         for (i=0;i<numErrors;i++) {
  1676.             CtoPstr(errorStr[i]);
  1677.             width = StringWidth((StringPtr)errorStr[i]);
  1678.             center = iBox.left + (iBox.right-iBox.left)/2;
  1679.             MoveTo(center - (width/2),iBox.top + (10*(i+1)));
  1680.             DrawString("\p! ");
  1681.             DrawString((StringPtr)errorStr[i]);
  1682.         }
  1683.         TextFont(saveFont);
  1684.         TextSize(saveSize);
  1685.         pasteError = kPasteOK;   // clear the flag
  1686.         invalidChar = false;     // ditto
  1687.         SysBeep(0);
  1688.     }
  1689.     
  1690.     /* clear the error count */
  1691.     numErrors = 0;
  1692. }
  1693.  
  1694. /* User item code for default buttons in dialogs */
  1695.  
  1696. pascal void OutlineButton (myWindow,itemNo)
  1697. WindowPtr myWindow;
  1698. short itemNo;
  1699. /* outliner for the ok button */
  1700. {
  1701.     short iType;
  1702.     Handle iHandle;
  1703.     Rect iBox;
  1704.     
  1705.     GetDItem(myWindow, itemNo, &iType, &iHandle, &iBox);
  1706.     InsetRect(&iBox, -4, -4);
  1707.     PenSize(3, 3);
  1708.     FrameRoundRect(&iBox, 16, 16);
  1709.     PenNormal();
  1710. }
  1711.  
  1712. /* ---------------- graf procs ---------------- */
  1713.  
  1714. /* replace normal drawing so that I can show a null character and CR 
  1715.    as an undefined character. */
  1716.    
  1717. pascal void MyStdText(byteCount,textBuf,numer,denom)
  1718. short    byteCount;
  1719. QDPtr    textBuf;
  1720. Point    numer,denom;
  1721. {
  1722.     short i;
  1723.     char c;
  1724.     
  1725.     for (i=0;i<byteCount;i++) {
  1726.         c = *(textBuf+i);
  1727.         if ((c==0)||(c==13))
  1728.             c = 255;
  1729.         StdText(1,&c,numer,denom);
  1730.     }
  1731. }
  1732.  
  1733. /* override this to give width to the null character and CR */
  1734.  
  1735. pascal short MyStdTextMeas(byteCount,textBuf,numer,denom,info)
  1736. short    byteCount;
  1737. QDPtr    textBuf;
  1738. Point    *numer,*denom;
  1739. FontInfo *info;
  1740. {
  1741.     short i,width;
  1742.     char c;
  1743.         
  1744.     SetPort(BCDialog);
  1745.     width = StdTxMeas(byteCount,textBuf,numer,denom,info);
  1746.     for (i=0;i<byteCount;i++) {
  1747.         c = *(textBuf+i);
  1748.         if ((c==0)||(c==13)) {
  1749.             c = 255;
  1750.             width = width + StdTxMeas(1,&c,numer,denom,info);
  1751.         }
  1752.     }
  1753.     return width;
  1754. }
  1755.  
  1756. /* ---------------- TE word break ---------------- */
  1757.  
  1758. /* don't break anywhere.  We want to 'text edit" even non-printing characters. */
  1759.  
  1760. pascal Boolean MyWordBreak(Ptr text,short charPos)
  1761. {
  1762.     return FALSE;
  1763. }
  1764.  
  1765.  
  1766. /* ScriptManager code from David Greenfield */
  1767.  
  1768. /************************************************************************/
  1769. void SyncKeyboard2Font(short fontID )
  1770. {
  1771.     short    fontScript;
  1772.     long    keyboard;
  1773.     
  1774.     if (!TrapAvailable(_ScriptUtil))
  1775.         return;
  1776.         
  1777.     fontScript = Font2Script( fontID );
  1778.     keyboard   = GetEnvirons( smKeyScript );
  1779.     
  1780.     if( keyboard != (long) fontScript )
  1781.         KeyScript( fontScript );
  1782. }
  1783.